<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-/bQdsTh/da6pkI1MST/rWKFNjaCP5gBSY4sEBT38Q/9RBh9AH40zEOg7Hlq2THRZ"
        crossorigin="anonymous"></script>

    <script src="https://unpkg.com/vue@next"></script>

    <main class="container">
        <div id="XmlEditorApp">

            <h1>以撒的结合items.xml在线编辑器</h1>

            <input type="file" @change='open_file' id='file_selector' hidden>
            <a id="save_file_href" hidden>save me</a>

            <button class="btn btn-link" @click='open'>打开XML</button>
            <button class="btn btn-link" @click='save'>保存XML</button>
            <hr>
            <div class='alert alert-primary'>
                请将下载后的xml文件放到您的mod文件夹的此位置：content\items.xml
                <hr>
                相对于忏悔游戏的完整路径为：The Binding of Isaac Rebirth\mods\<code>您的mod名称</code>\content\items.xml
                <hr>
                你可以打开游戏解包后的xml来参考。
            </div>
            <div class="card">
                <div class="card-body">
                    <label for='xml-root' class="form-label">根目录： </label>
                    <input id='xml-root' class="form-control" v-model="xmlprops.gfxroot" />

                    <label for='xml-portraitroot' class="form-label">版本号： </label>
                    <input id='xml-portraitroot' class="form-control" v-model="xmlprops.version" />

                </div>
            </div>
            <div class="card">

                <div class="list-group">
                    <template v-for="(xml,i) in xmls">
                        <button :class='"list-group-item list-group-item-action"+(editing==i?" active":"")'
                            @click='editing=i'>
                            编辑道具{{i+1}}({{xml.name}})
                        </button>
                    </template>

                    <button class='list-group-item list-group-item-action list-group-item-success'
                        @click='new_xml'>增加新道具</button>
                </div>
                <div v-for="(xml,i) in xmls">
                    <span v-if='editing == i'>
                        <div class="card-body">
                            <h1>道具 {{ editing+1 }}
                                <button @click='remove_xml(i)' class="btn btn-sm btn-danger">删除此道具</button>
                            </h1>

                            <hr>

                            <label :for='"xml-itemtype-"+i'>道具类型： </label>

                            <select class="form-select" aria-label="Default select example" :id='"xml-itemtype-"+i'
                                v-model="xml.item_type">
                                <option value="passive">被动道具</option>
                                <option value="active">主动道具</option>
                                <option value="familiar">跟班道具</option>
                                <option value="trinket">饰品道具</option>
                                <option value="null">无值道具</option>
                            </select>

                            <hr>

                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='id' name='道具id'
                            desc='一般不要指定道具id'></list-item-text>

                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='name' name='道具名'
                                desc='道具的名字'></list-item-text>

                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='description' name='道具描述'
                                desc='道具的描述'></list-item-text>
                            <!-- cache -->
                            <list-item-multioption :i='i' :xml='xmls[editing]' xmlname='cache' name='属性缓存' desc='道具会影响到角色的哪些属性'
                            :options='caches_texts' propobj='caches'>
                            </list-item-multioption>

                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='gfx' name='道具图片的位置'
                                desc=''><ensure-desc>{{xmlprops.gfxroot + xmls[editing].gfx}}</ensure-desc></list-item-text>

                            <!-- tags -->
                            <list-item-multioption :i='i' :xml='xmls[editing]' xmlname='tags' name='标记' desc=''
                            :options='tags_texts' propobj='tags'>
                            </list-item-multioption>

                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='bombs' name='炸弹' desc='炸弹数量'>
                            </list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='keys' name='钥匙' desc='钥匙数量'>
                            </list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='coins' name='金币' desc='金币数量'>
                            </list-item-text>

                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='hearts' name='红心数量' desc=''>
                            </list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='soulhearts' name='魂心数量' desc=''>
                            </list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='blackhearts' name='黑心数量' desc=''>
                            </list-item-text>

                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='maxhearts' name='心之容器数量' desc='增加的血量上限数（默认是空的）'>
                            </list-item-text>

                            <list-item-option :i='i' :xml='xmls[editing]' xmlname='chargetype' name='充能类型' desc=''
                            :options='[["normal","正常"],["timed","缓慢充能"], ["special","特殊"]]'>
                            </list-item-option>

                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='cooldown' name='冷却' desc='两次效果之间的冷却时间'>
                            </list-item-text>
                            <list-item-bool :i='i' :xml='xmls[editing]' xmlname='passivecache' name='重新计算属性缓存' desc='捡起道具的时候重新计算角色的属性'>
                            </list-item-bool>
                            <list-item-bool :i='i' :xml='xmls[editing]' xmlname='special' name='特殊道具' desc=''>
                            </list-item-bool>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='initcharge' name='初始充能' desc='例如：道具“Everything Jar”'>
                            </list-item-text>
                            <list-item-option :i='i' :xml='xmls[editing]' xmlname='devilprice' name='恶魔价格' desc='可以填写1或者2'
                            :options='["1","2"]'>
                            </list-item-option>


                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='shopprice' name='商店价格' desc=''>
                            </list-item-text>
                            <list-item-bool :i='i' :xml='xmls[editing]' xmlname='addcostumeonpickup' name='捡起时增加套装' desc=''>
                            </list-item-bool>

                            <list-item-bool :i='i' :xml='xmls[editing]' xmlname='persistent' name='持久效果' desc='道具的效果可以跨越房间'>
                            </list-item-bool>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='achievement' name='成就id' desc='将道具绑定到成就id上'>
                            </list-item-text>
                            <list-item-option :i='i' :xml='xmls[editing]' xmlname='quality' name='品质' desc='道具的品质'
                            :options='["0","1","2","3","4"]'>
                            </list-item-option>
                            <list-item-bool :i='i' :xml='xmls[editing]' xmlname='hidden' name='隐藏' desc='阻止道具出现在道具底座上，比如“Sumptorium”或者“Bag of Crafting”'>
                            </list-item-bool>


                        </div>
                    </span>
                </div>

            </div>
        </div>

        <hr>
        <p>
            更多内容见<a class="btn btn-sm btn-link" href="http://frto027.gitee.io/isaac-editors/">Frto027的以撒Mod工具集合</a>

            <br>
            这里是Frto027，如果你想要获取此页上数据更多详细信息，请通过<a href="https://space.bilibili.com/11948678">B站</a>、<a
                href="https://github.com/frto027">Github</a>、<a href="https://gitee.com/frto027/">Gitee</a>、<a
                href="https://tieba.baidu.com/home/main?un=602706150">贴吧</a>等渠道联系我。
            <br>
        
            页面UI使用<a class="btn btn-link btn-sm" href="https://v3.vuejs.org/">vue</a>和<a class="btn btn-link btn-sm" href="https://getbootstrap.com/">bootstrap</a>潦草绘制
                
    
        </p>

    </main>


    <script>
        const BoolProps = ['persistent', 'passivecache','special','addcostumeonpickup', 'hidden']
        const PlayerEditor = {
            data() {
                return {
                    editing: -1,
                    xmls: [
                    ],
                    xmlprops: {
                        gfxroot: "gfx/items/",
                        version: "1",
                    },
                    caches_texts:[
                        ["firedelay","firedelay"],
                        ["damage","damage"],
                        ["speed","speed"],
                        ["range","range"],
                        ["tearcolor","tearcolor"],
                        ["tearflag","tearflag"],
                        ["color","color"],
                        ["size","size"],
                        ["shotspeed","shotspeed"],
                        ["all","all"],
                        ["luck","luck"],
                        ["flying","flying"],
                        ["weapon","weapon"],
                        ["familiars","familiars"]
                    ],
                    tags_texts:[
                        ["angel","angel"],
                        ["baby","baby"],
                        ["battery","battery"],
                        ["bob","bob"],
                        ["book","book"],
                        ["dead","dead"],
                        ["devil","devil"],
                        ["fly","fly"],
                        ["food","food"],
                        ["guppy","guppy"],
                        ["mom","mom"],
                        ["monstermanual","monstermanual"],
                        ["mushroom","mushroom"],
                        ["nocantrip","nocantrip"],
                        ["nogreed","nogreed"],
                        ["nokeeper","nokeeper"],
                        ["nolostbr","nolostbr"],
                        ["offensive","offensive"],
                        ["poop","poop"],
                        ["quest","quest"],
                        ["spider","spider"],
                        ["stars","stars"],
                        ["summonable","summonable"],
                        ["syringe","syringe"],
                        ["tearsup","tearsup"],
                        ["tech","tech"],
                        ["uniquefamiliar","uniquefamiliar"]
                    ]

                }
            },
            methods: {
                new_xml() {
                    this.xmls.push(
                        {
                            item_type:"passive",
                            
                            
                            use_cache:true,
                            //cache:"firedelay" ,
                            caches:{
                                firedelay:true,
                            },

                            tags:{

                            },

                            use_description:true,
                            description:"Tears up" ,
                            
                            use_gfx:true,
                            gfx:"Collectibles_001_TheSadOnion.png" ,
                            
                            // use_id:true,
                            // id:"1" ,
                            
                            use_name:true,
                            name:"The Sad Onion"
                        }
                    )
                },
                remove_xml(i) {
                    if (confirm('要删除道具“' + this.xmls[i].name + '”吗？')) {
                        for (let j = i; j < this.xmls.length - 1; j++) {
                            this.xmls[j] = this.xmls[j + 1]
                        }
                        this.xmls.length = this.xmls.length - 1
                        this.editing = -1
                        alert("已删除")
                    }
                },
                open() {
                    document.getElementById('file_selector').click()
                },
                async open_file(e) {
                    let text = await (e.target.files[0].text());
                    let parser = new DOMParser()
                    let xml = parser.parseFromString(text, 'application/xml')

                    if (xml.children[0] == undefined || xml.children[0].tagName !== "items") {
                        alert("文件错误：不是items.xml或文件格式不正确")
                        return
                    }

                    let data = []
                    for (let child of xml.children[0].children) {
                        let tag_filter = [
                            "passive",
                            "active",
                            "familiar",
                            "trinket",
                            "null",
                        ]
                        if (tag_filter.indexOf(child.tagName) == -1) {
                            alert("文件错误：不是items.xml或文件格式不正确（存在不认识的标签）")
                            return
                        }
                        let data_item = {}
                        data_item.item_type = child.tagName

                        for (let attr of child.getAttributeNames()) {
                            data_item['use_' + attr] = true
                            let value = child.getAttribute(attr)

                            if(attr == 'cache'){
                                //parse cache
                                data_item.caches = data_item.caches || {}
                                for(let cache of value.split(' ')){
                                    if(cache.length > 0){
                                        data_item.caches[cache] = true
                                    }
                                }
                                continue
                            }
                            if(attr == 'tags'){
                                //parse cache
                                data_item.tags = data_item.tags || {}
                                for(let tag of value.split(' ')){
                                    if(tag.length > 0){
                                        data_item.tags[tag] = true
                                    }
                                }
                                continue
                            }

                            if (BoolProps.indexOf(attr) != -1) {
                                value = value == 'true'
                            }
                            data_item[attr] = value
                        }


                        data_item.caches = data_item.caches || {}
                        data_item.tags = data_item.tags || {}

                        data.push(data_item)
                    }
                    this.xmls = data
                    this.xmlprops.gfxroot = xml.children[0].getAttribute('gfxroot')
                    this.xmlprops.version = xml.children[0].getAttribute('version')
                },
                save() {
                    let xmlroot = document.implementation.createDocument('', '', null)
                    items = xmlroot.createElement('items')
                    for (let prop in this.xmlprops) {
                        items.setAttribute(prop, this.xmlprops[prop])
                    }
                    xmlroot.appendChild(items)

                    for (let item of this.xmls) {
                        let itemNode = xmlroot.createElement(item.item_type)
                        items.appendChild(itemNode)

                        for (let props in item) {
                            if (!(props.startsWith('use_'))) {
                                continue
                            }
                            if (item[props] == undefined || item[props] == false) {
                                continue
                            }
                            let props_actual = props.substr(4)
                            let props_value = item[props_actual]

                            if (props_actual == 'cache') {
                                let tag_str = undefined
                                for(let tag_name in item.caches){
                                    if(item.caches[tag_name]){
                                        if(tag_str == undefined){
                                            tag_str = ''
                                        }else{
                                            tag_str += ' '
                                        }
                                        tag_str += tag_name
                                    }
                                }
                                itemNode.setAttribute('cache',tag_str || '')
                                continue
                            }
                            if (props_actual == 'tags') {
                                let tag_str = undefined
                                for(let tag_name in item.tags){
                                    if(item.tags[tag_name]){
                                        if(tag_str == undefined){
                                            tag_str = ''
                                        }else{
                                            tag_str += ' '
                                        }
                                        tag_str += tag_name
                                    }
                                }
                                itemNode.setAttribute('tags',tag_str || '')
                                continue
                            }
                            if (props_value == undefined) {
                                continue
                            }

                            if (BoolProps.indexOf(props_actual) != -1) {
                                props_value = props_value ? 'true' : 'false'
                            }

                            itemNode.setAttribute(props_actual, props_value)
                        }
                    }


                    let save_xml_text = new XMLSerializer().serializeToString(xmlroot)
                    var save_file_href = document.getElementById("save_file_href")
                    save_file_href.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(save_xml_text));
                    save_file_href.setAttribute('download', 'items.xml');
                    save_file_href.click()
                }
            }
        }



        let app = Vue.createApp(PlayerEditor)
            .component('ensure-desc', {
                template: `请确保resources/<slot></slot>存在`
            })
            .component('list-item-text', {
                props: ['xmlname', 'desc', 'name', 'listseq', 'xml', 'i'],
                template: `
                        <div class="form-check form-switch">
                        <input class="form-check-input" type="checkbox" value="" :id='"xml-use-"+name+"-"+i' v-model="xml['use_'+xmlname]">
                        <label class="form-check-label" :for='"xml-use-"+name+"-"+i'>
                            指定“{{name}}”
                        </label>
                        </div>
                        <template v-if="xml['use_'+xmlname]">
                            <label class="form-label" :for='"xml-"+name+"-"+i' >{{name}}： </label>
                            <input class="form-control" :id='"xml-"+name+"-"+i' v-model="xml[xmlname]" />
                            <div>{{desc}} <br> <slot></slot></div>
                        </template>

                        <hr>
                    `
            })
            .component('list-item-bool',{
                props: ['xmlname', 'desc', 'name', 'listseq', 'xml', 'i'],
                template:`
                    <div class="form-check form-switch">
                    <input class="form-check-input" type="checkbox" value="" :id='"xml-use-"+name+"-"+i' v-model="xml['use_'+xmlname]">
                    <label class="form-check-label" :for='"xml-use-"+name+"-"+i'>
                        指定“{{name}}”
                    </label>
                    </div>
                    <div class="form-check form-check-inline" v-if="xml['use_'+xmlname]">
                        <input type="checkbox" class="form-check-input" :id='"xml-"+name+"-"+i' v-model="xml[xmlname]" />
                        <label class="form-check-label" :for='"xml-"+name+"-"+i' >{{name}}</label>
                        <div>{{desc}} <br> <slot></slot></div>
                    </div>

                    <hr>
                `
            })
            .component('list-item-option',{
                props: ['xmlname', 'desc', 'name','options', 'listseq', 'xml', 'i'],
                template:`
                    <div class="form-check form-switch">
                    <input class="form-check-input" type="checkbox" value="" :id='"xml-use-"+name+"-"+i' v-model="xml['use_'+xmlname]">
                    <label class="form-check-label" :for='"xml-use-"+name+"-"+i'>
                        指定“{{name}}”
                    </label>
                    </div>
                    <template v-if="xml['use_'+xmlname]">

                        <label :for='"xml-"+name+"-"+i'>{{name}}： </label>

                        <select class="form-select" aria-label="Default select example" :id='"xml-"+name+"-"+i'
                        v-model="xml[xmlname]">

                            <option v-for="des of options" :value="des instanceof Array ? des[0] : des">{{des instanceof Array ? (des[1] || des[0]): des}}</option>
                        </select>
                        <div>{{desc}} <br> <slot></slot></div>

                    </template>

                    <hr>
                `
            })
            .component('list-item-multioption',{
                props: ['xmlname', 'desc', 'name','options', 'xml','propobj', 'i'],
                template:`
                    <div class="form-check form-switch">
                    <input class="form-check-input" type="checkbox" value="" :id='"xml-use-"+name+"-"+i' v-model="xml['use_'+xmlname]">
                    <label class="form-check-label" :for='"xml-use-"+name+"-"+i'>
                        指定“{{name}}”
                    </label>
                    </div>
                    <template v-if="xml['use_'+xmlname]">

                        <label>{{name}}： </label>

                            <div class="form-check form-check-inline" v-for="des of options">
                                <label class="form-check-label" :for='"xml-option-"+name+"-" + des + "-" +i'>{{des instanceof Array ? (des[1] || des[0]): des}}</label>
                                <input class="form-check-input" type="checkbox" value="" :id='"xml-option-"+name+"-" + des + "-" +i' v-model="xml[propobj][des instanceof Array ? des[0] : des]">

                            </div>
                        <div>{{desc}} <br> <slot></slot></div>

                    </template>

                    <hr>
                `
            })

            .mount('#XmlEditorApp')
    </script>

</body>

</html>